#! /usr/bin/env python2
# -*- coding: utf-8 -*-
import sys, os, time, thread
import glib, gobject
import pygst
pygst.require("0.10")
import gst
import mutagen
import threading

from PyQt4.QtCore import *
from PyQt4.QtGui import *

class TagReader():
		
	def getTag(self, fileName):
		try:
			tags = mutagen.File(unicode(fileName), easy=True)
		except mutagen.mp3.HeaderNotFoundError:
			return None
		
		if tags == None: return None
		
		try:
			artist = tags['artist'][0]
		except KeyError: artist = None
		try:
			title = tags['title'][0]
		except KeyError: title = None
		if artist == None and title == None: return None
		elif artist == None: return title
		elif title == None: return artist
		else: return artist + ' - ' + title

class Player(QWidget, object):
	def __init__(self, parent=None):
		super(Player, self).__init__(parent)
		self.buffering = False
		self.bufferTimer = None
		self.playBin = gst.element_factory_make("playbin2", "playBin")
		fakesink = gst.element_factory_make("fakesink", "fakesink")
		self.playBin.set_property("video-sink", fakesink)
		self.playBin.set_property("buffer-size", 256000000)
		self.playBin.set_property("buffer-duration", 128000000)
		self.playMode = False
		self.seaking = True
		bus = self.playBin.get_bus()
		bus.add_signal_watch()
		bus.connect("message", self.on_message)
		bus.connect('message::tag', self.on_tag)
		self.playBin.connect("source-setup", self.onSource)
		self.playBin.connect("about-to-finish", self.aboutFinish)
#How-to send signals:
		#~ self.startEvent = gst.event_new_flush_start()
		#~ self.stopEvent = gst.event_new_flush_stop()
		#~ print gst.element_send_event(self.playBin, self.startEvent)
		#~ print gst.element_send_event(self.playBin, self.stopEvent)
		#~ print self.playBin.send_event(self.startEvent)
		#~ print self.playBin.send_event(self.stopEvent)
		
	def timerEvent(self, timeEvent):
		###prt "TIMER EVENT"
		self.playBin.set_state(gst.STATE_NULL)
		time.sleep(0.1)
		self.playBin.set_property("uri", self.filename)
		self.playBin.set_state(gst.STATE_PLAYING)
		
	
	def aboutFinish(playerObj, data):
		print "About-to-Finish"
		
	def play(self, File):
		if self.bufferTimer !=None:
				self.killTimer(self.bufferTimer)
				self.bufferTimer = None
				#prt "TIMER STOPPED"
		self.playBin.set_state(gst.STATE_READY)
		self.filename = unicode(File)
		self.playMode = True
		self.playBin.set_property("uri", self.filename)
		self.playBin.set_state(gst.STATE_PLAYING)
		self.play_thread_id = thread.start_new_thread(self.play_thread, ())
		
	def pause(self):
		state = self.playBin.get_state()
		if state[1] == gst.STATE_NULL: pass
		else:
			if self.playMode == True:
				self.playBin.set_state(gst.STATE_PAUSED)
				self.playMode = False
			else:
				self.playBin.set_state(gst.STATE_PLAYING)
				self.playMode = True
			if self.bufferTimer !=None:
				self.killTimer(self.bufferTimer)
				self.bufferTimer = None
				#prt "TIMER STOPPED"
	
	def stop(self):
		self.play_thread_id = None
		self.playBin.set_state(gst.STATE_NULL)
		self.playMode = False
		if self.bufferTimer !=None:
				self.killTimer(self.bufferTimer)
				self.bufferTimer = None
				#prt "TIMER STOPPED"
			
	def play_thread(self):
		play_thread_id = self.play_thread_id
		self.emit(SIGNAL("newTimeTag(QString)"), QString("00:00 - 00:00"))
		while play_thread_id == self.play_thread_id:
			try:
				time.sleep(0.2)
				dur_int = self.playBin.query_duration(gst.FORMAT_TIME, None)[0]
			except gst.QueryError: 
				continue
			dur_str = self.convert_ns2str(dur_int)
			self.emit(SIGNAL("newDuration(int)"), dur_int/10000000)
			if self.radio == True:
				self.emit(SIGNAL("newTimeTag(QString)"), QString("00:00 - " + "00:00"))
			else:
				self.emit(SIGNAL("newTimeTag(QString)"), QString("00:00 - " + dur_str))
			break
		time.sleep(0.2)
		while play_thread_id == self.play_thread_id:
			try:
				pos_int = self.playBin.query_position(gst.FORMAT_TIME, None)[0]
			except gst.QueryError:
				time.sleep(0.2)
				continue
			pos_str = self.convert_ns2str(pos_int)
			if play_thread_id == self.play_thread_id:
				if self.seaking == True:
					self.emit(SIGNAL("newTimePosition(int)"), pos_int/10000000)
				if self.radio == True:
					self.emit(SIGNAL("newTimeTag(QString)"), QString(pos_str + ' - ' + "00:00"))
				else:
					self.emit(SIGNAL("newTimeTag(QString)"), QString(pos_str + " - " + dur_str))
			time.sleep(0.1)
		self.emit(SIGNAL("newTimePosition(int)"), 0)
		self.emit(SIGNAL("newTimeTag(QString)"), QString("00:00 - 00:00"))
						
	def on_message(self, bus, message):
		t = message.type
		if t == gst.MESSAGE_EOS:
			#prt "EOS!!!"
			if self.radio == True:
				self.playBin.set_state(gst.STATE_NULL)
				time.sleep(0.1)
				self.playBin.set_property("uri", self.filename)
				self.playBin.set_state(gst.STATE_PLAYING)
			else:
				self.play_thread_id = None
				self.playBin.set_state(gst.STATE_NULL)
				self.playMode = False
				self.emit(SIGNAL("eos()"))
			if self.bufferTimer !=None:
				self.killTimer(self.bufferTimer)
				self.bufferTimer = None
				#prt "TIMER STOPPED"
			
		elif t == gst.MESSAGE_ERROR:
			#prt 'Error'
			if self.radio == True:
				self.playBin.set_state(gst.STATE_NULL)
				time.sleep(0.1)
				self.playBin.set_property("uri", self.filename)
				self.playBin.set_state(gst.STATE_PLAYING)
			else:
				self.play_thread_id = None
				self.playBin.set_state(gst.STATE_NULL)
				err, debug = message.parse_error()
				#prt "Error: %s" % err, debug
				self.playMode = False
			if self.bufferTimer !=None:
				self.killTimer(self.bufferTimer)
				self.bufferTimer = None
				#prt "TIMER STOPPED"
				
		elif t == gst.MESSAGE_STATE_CHANGED:
			tag = message.parse_state_changed()
			#prt 'STATE_CHANGED:  {}'.format(tag)
			#~ print 'STATE_CHANGED: New STATE: {}'.format(tag[1])
			#~ print 'STATE_CHANGED: Pending:   {}'.format(tag[2])

		elif t == gst.MESSAGE_STREAM_STATUS:
			tag = message.parse_stream_status()
			#prt 'STREAM_STATUS: {}'.format(tag[0])
			if tag[0] == gst.STREAM_STATUS_TYPE_LEAVE:
				self.playBin.set_state(gst.STATE_NULL)
				time.sleep(0.1)
				self.playBin.set_property("uri", self.filename)
				self.playBin.set_state(gst.STATE_PLAYING)
			if self.bufferTimer !=None:
				self.killTimer(self.bufferTimer)
				self.bufferTimer = None
				#prt "TIMER STOPPED"

		elif t == gst.MESSAGE_WARNING:
			#prt "WARNING"
			if self.radio == True:
				self.playBin.set_state(gst.STATE_NULL)
				time.sleep(0.1)
				self.playBin.set_property("uri", self.filename)
				self.playBin.set_state(gst.STATE_PLAYING)
			else:
				self.play_thread_id = None
				self.playBin.set_state(gst.STATE_NULL)
				self.playMode = False
			if self.bufferTimer !=None:
				self.killTimer(self.bufferTimer)
				self.bufferTimer = None
				#prt "TIMER STOPPED"

		elif t == gst.MESSAGE_BUFFERING:
			tag = message.parse_buffering()
			#prt "Buffer: {}".format(tag)
			self.emit(SIGNAL("buffer(int)"), int(tag))
			if tag < 10 and self.bufferTimer == None:
				self.bufferTimer = self.startTimer(1000)
				#prt "TIMER STARTED"
			if tag < 10 and self.buffering == False:
				self.buffering = True
				self.playBin.set_state(gst.STATE_PAUSED)
			if tag > 10:
				if self.bufferTimer !=None:
					self.killTimer(self.bufferTimer)
					self.bufferTimer = None
					#prt "TIMER STOPPED"
			if tag > 80:
				if self.buffering == True:
					self.buffering = False
					self.playBin.set_state(gst.STATE_PLAYING)
				if self.bufferTimer !=None:
					self.killTimer(self.bufferTimer)
					self.bufferTimer = None
					#prt "TIMER STOPPED"
		else: print t
			
	def on_tag(self, bus, msg):
		taglist = msg.parse_tag()
		try:
			artist = unicode(taglist['artist'])
		except KeyError: artist = None
		try:
			title = unicode(taglist['title'])
		except KeyError: title = None
		if artist == None and title == None: pass 
		elif artist == None:
			tags = title
			self.emit(SIGNAL("newTags(QString)"), QString(tags))
		elif title == None:
			tags = artist
			self.emit(SIGNAL("newTags(QString)"), QString(tags))
		else:
			tags = artist + ' - ' + title
			self.emit(SIGNAL("newTags(QString)"), QString(tags))
			
	def onSource(playerObj, pipelineObj, srcObj):
		source = str(srcObj.__class__())
		if "GstSoupHTTPSrc" in source:
			playerObj.radio = True
			srcObj.set_property("iradio-mode", True)
			srcObj.set_property("timeout", 1200)
		else:
			playerObj.radio = False
			
	def changeSeaking(self, status):
		if type(status) is bool:
			self.seaking = status
		else: pass
	
	def changeTrackPosition(self, pos):
		position = pos*10000000
		self.playBin.seek_simple(gst.FORMAT_TIME, gst.SEEK_FLAG_FLUSH, position)
		
	def getVolume(self):
		volume = self.playBin.get_property("volume")
		print "Get Vol {}".format(volume)
		return int(volume*100)
		
	def setVolume(self, vol):
		volume = vol/100.0
		self.playBin.set_property("volume", volume)
		print "Set Vol {}".format(volume)
			
	def convert_ns2str(self, t):
		# This method was submitted by Sam Mason.
		# It's much shorter than the original one.
		s,ns = divmod(t, 1000000000)
		m,s = divmod(s, 60)

		if m < 60:
			return "%02i:%02i" %(m,s)
		else:
			h,m = divmod(m, 60)
			return "%i:%02i:%02i" %(h,m,s)
		
	def convert_ns2int(self, t):
		# This method was submitted by Sam Mason.
		# It's much shorter than the original one.
		s,ns = divmod(t, 1000000000)
		m,s = divmod(s, 60)

		if m < 60:
			return m*60 + s
		else:
			h,m = divmod(m, 60)
			return 24*h + 60*m + s

class FileSystemBrowser(QTableView):
	def __init__(self, parent=None):
		super(FileSystemBrowser, self).__init__(parent)
		self.Index = QModelIndex()
				
	def keyPressEvent(self, e):
		QWidget.keyPressEvent(self, e)
		key = e.key()
		#~ e.ignore()
		if key == Qt.Key_A:
			currentPath = self.model().filePath(self.currentIndex())
			currentName = self.model().fileName(self.currentIndex())
			if self.model().isDir(self.currentIndex()):
				self.emit(SIGNAL("addFolder(QString)"), currentPath)
			else:
				if currentPath.endsWith(".m3u"):
					self.emit(SIGNAL("addM3U(QString)"), currentPath)
				else:
					self.emit(SIGNAL("addFile(QString, QString)"), "file://" + currentPath, currentName )
		
		#~ if key == Qt.Key_Tab:
			#~ e.ignore()
		elif key == Qt.Key_Return or key == Qt.Key_Enter:
			self.enterItem()
		elif key == Qt.Key_Backspace:
			self.setCurrentIndex(self.rootIndex())
			self.setRootIndex(self.rootIndex().parent())
		elif key == Qt.Key_Down:
			try:
				self.selectRow(self.selectedIndexes()[0].row()+1)
			except IndexError:
				self.selectRow(0)
		elif key ==Qt.Key_Up:
			try:
				self.selectRow(self.selectedIndexes()[0].row()-1)
			except IndexError:
				self.selectRow(0)

		
	def enterItem(self):
		if self.model().isDir(self.currentIndex()):
			self.setRootIndex(self.currentIndex())
			#~ path = self.model().filePath(self.rootIndex())
			#~ newPath = QDir(path).entryList()
			#~ index = self.model().index(path + '/' + newPath[2])
			#~ self.setCurrentIndex(index)

	def mouseDoubleClickEvent(self, e):
		self.enterItem()
		
	def focusOutEvent(self, e):
		QTableView.focusOutEvent(self, e)
		self.Index = self.currentIndex()
		self.clearSelection()	
	
	def focusInEvent(self, e):
		QTableView.focusInEvent(self, e)
		self.setCurrentIndex(self.Index)
		try:
				self.selectedIndexes()[0]
		except IndexError:
				self.setCurrentIndex(self.rootIndex().child(0,0))

		

class PlayList(FileSystemBrowser):
	def __init__(self, parent=None):
		super(PlayList, self).__init__(parent)
		self.playItem = None
	
	def keyPressEvent(self, e):
		QWidget.keyPressEvent(self, e)
		key = e.key()
		#~ e.ignore()
		if key == Qt.Key_D:
			self.delItem()
		elif key == Qt.Key_Return or key == Qt.Key_Enter:
			self.enterItem()
		elif key == Qt.Key_C:
			self.removeAll()
		elif key == Qt.Key_Down:
			try:
				self.selectRow(self.selectedIndexes()[0].row()+1)
			except IndexError:
				self.selectRow(0)
		elif key == Qt.Key_Up:
			try:
				self.selectRow(self.selectedIndexes()[0].row()-1)
			except IndexError:
				self.selectRow(0)
		#~ e.ignore()
	
	def enterItem(self):
		try:
			filename = self.model().itemFromIndex(self.currentIndex()).child(0,0).text()
			tags = self.model().itemFromIndex(self.currentIndex()).text()
		except AttributeError: pass
		else:
			if self.playItem != None:
				font = self.playItem.font()
				font.setBold(False)
				self.playItem.setFont(font)
			self.emit(SIGNAL("playSong(QString, QString)"), filename, tags)
			self.playItem = self.model().itemFromIndex(self.currentIndex())
			font = self.playItem.font()
			font.setBold(True)
			self.playItem.setFont(font)
			
	def nextSong(self):
		try:
			font = self.playItem.font()
			font.setBold(False)
			self.playItem.setFont(font)
			newRow = self.playItem.row()+1
			index = self.model().index(newRow, 0)
			self.playItem = self.model().itemFromIndex(index)
			try:
				filename = self.playItem.child(0,0).text()
				tags = self.playItem.text()
			except AttributeError:
				self.playItem = self.model().itemFromIndex(self.model().index(0,0))
				filename = self.playItem.child(0,0).text()
				tags = self.playItem.text()
			self.emit(SIGNAL("playSong(QString, QString)"), filename, tags)
			font.setBold(True)
			self.playItem.setFont(font)
		except AttributeError: pass

		
	def prevSong(self):
		try:
			if self.playItem.row() !=0:
				font = self.playItem.font()
				font.setBold(False)
				self.playItem.setFont(font)
				newRow = self.playItem.row()-1
				index = self.model().index(newRow, 0)
				self.playItem = self.model().itemFromIndex(index)
			else: 
				self.playItem = self.playItem = self.model().itemFromIndex(self.model().index(0,0))
				font = self.playItem.font()
			filename = self.playItem.child(0,0).text()
			tags = self.playItem.text()
			self.emit(SIGNAL("playSong(QString, QString)"), filename, tags)
			font.setBold(True)
			self.playItem.setFont(font)
		except AttributeError: pass

		
	def play(self):
		try:
			filename = self.model().itemFromIndex(self.currentIndex()).child(0,0).text()
			tags = self.model().itemFromIndex(self.currentIndex()).text()
		except AttributeError: pass
		else:
			if self.playItem != None:
				font = self.playItem.font()
				font.setBold(False)
				self.playItem.setFont(font)
			self.emit(SIGNAL("playSong(QString, QString)"), filename, tags)
			self.playItem = self.model().itemFromIndex(self.currentIndex())
			font = self.playItem.font()
			font.setBold(True)
			self.playItem.setFont(font)
	
	def delItem(self):
		currentItem = self.model().itemFromIndex(self.currentIndex())
		self.model().removeRows(self.currentIndex().row(), 1)
		if self.model().rowCount() == 0 or self.playItem == currentItem:
			self.playItem = None
	def removeAll(self):
		self.model().removeRows(0, self.model().rowCount())
		self.playItem = None
		
	
class MainWidget(QWidget):
	def __init__(self, rootPath, parent=None):
		super(MainWidget, self).__init__(parent)
		self.rootPath = rootPath
		self.playCore = Player(self)

#Song Label:
		self.SongLabel = QLabel()
		sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred)
		sizePolicy.setHorizontalStretch(0)
		sizePolicy.setVerticalStretch(0)
		sizePolicy.setHeightForWidth(self.SongLabel.sizePolicy().hasHeightForWidth())
		self.SongLabel.setSizePolicy(sizePolicy)
		#~ self.SongLabel.setFrameShape(QFrame.StyledPanel)
		#~ self.SongLabel.setFrameShadow(QFrame.Sunken)
		self.SongLabel.setFrameStyle(QFrame.NoFrame)
		self.SongLabel.setText("<font size=4><b>" + "Artist - Title" + "</b></font>")
		self.SongLabel.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignVCenter)
		self.SongLabel.setObjectName("SongLabel")
		

#Time Label:
		self.TimeLabel = QLabel()
		sizePolicy = QSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
		sizePolicy.setHorizontalStretch(0)
		sizePolicy.setVerticalStretch(0)
		sizePolicy.setHeightForWidth(self.TimeLabel.sizePolicy().hasHeightForWidth())
		self.TimeLabel.setSizePolicy(sizePolicy)
		#~ self.TimeLabel.setFrameShape(QFrame.StyledPanel)
		#~ self.TimeLabel.setFrameShadow(QFrame.Sunken)
		self.TimeLabel.setFrameStyle(QFrame.NoFrame)
		self.TimeLabel.setLineWidth(2)
		self.TimeLabel.setMidLineWidth(1)
		self.TimeLabel.setText("<font size=3><b>" + "00:00 - 00:00" + "</b></font>")
		self.TimeLabel.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
		self.TimeLabel.setObjectName("TimeLabel")
		
#Track Slider:
		self.TrackSlider = QSlider()
		self.TrackSlider.setOrientation(Qt.Horizontal)
		self.TrackSlider.setObjectName("TrackSlider")
		self.TrackSlider.setFocusPolicy(Qt.NoFocus)
		self.TrackSlider.setMinimum(0)
		self.TrackSlider.setTickInterval(1)
		self.TrackSlider.setSingleStep(1)
		
#Files Label:
		self.FilesLabel = QLabel()
		self.FilesLabel.setText("Files")
		self.FilesLabel.setObjectName("Files")
		
#FileFilters:
		self.FileFilter_1 = QStringList()
		self.FileFilter_1.append("*.ogg") #Checked
		self.FileFilter_1.append("*.mp3") #Checked
		self.FileFilter_1.append("*.m3u")
		#~ self.FileFilter_1.append("*.asf")
		#~ self.FileFilter_1.append("*.flac")
		#~ self.FileFilter_1.append("*.m4a")
		#~ self.FileFilter_1.append("*.ape")
		#~ self.FileFilter_1.append("*.mpc")
		#~ self.FileFilter_1.append("*.mp+")
		#~ self.FileFilter_1.append("*.mpp")
		#~ self.FileFilter_1.append("*.wma")
		#~ self.FileFilter_1.append("*.oga")
		#~ self.FileFilter_1.append("*.spx")
		#~ self.FileFilter_1.append("*.tta")
		#~ self.FileFilter_1.append("*.wv")
		#~ self.FileFilter_1.append("*.ofr")
		#~ self.FileFilter_1.append("*.bwf")
		#~ self.FileFilter_1.append("*.dls")
		#~ self.FileFilter_1.append("*.kar")
		#~ self.FileFilter_1.append("*.m1a")
		#~ self.FileFilter_1.append("*.m4a")
		#~ self.FileFilter_1.append("*.m4b")
		#~ self.FileFilter_1.append("*.mid")
		#~ self.FileFilter_1.append("*.midi")
		#~ self.FileFilter_1.append("*.mka")
		#~ self.FileFilter_1.append("*.mp1")
		#~ self.FileFilter_1.append("*.mp2")
		#~ self.FileFilter_1.append("*.mpa")
		#~ self.FileFilter_1.append("*.mpga")
		#~ self.FileFilter_1.append("*.mpu")
		#~ self.FileFilter_1.append("*.r1m")
		#~ self.FileFilter_1.append("*.ra")
		#~ self.FileFilter_1.append("*.ram")
		#~ self.FileFilter_1.append("*.raw")
		#~ self.FileFilter_1.append("*.rmf")
		#~ self.FileFilter_1.append("*.rmi")
		#~ self.FileFilter_1.append("*.smf")
		#~ self.FileFilter_1.append("*.sng")
		#~ self.FileFilter_1.append("*.swa")
		self.FileFilter_2 = QStringList()
		self.FileFilter_2.append("*.ogg") 
		self.FileFilter_2.append("*.mp3") 

#FileSystemModel:
		self.FileSystemModel = QFileSystemModel()
		self.FileSystemModel.setRootPath(QDir.rootPath())
		self.FileSystemModel.setNameFilters(self.FileFilter_1)
		#~ self.FileSystemModel.rootDirectory().setNameFilters(self.FileFilter_1)
		self.FileSystemModel.setNameFilterDisables(False)
		
#File Browser:
		self.FileBrowser = FileSystemBrowser()
		self.FileBrowser.setModel(self.FileSystemModel)
		self.FileBrowser.setMinimumSize(QSize(330, 300))
		self.FileBrowser.setObjectName("FileBrowser")
		#~ self.FileBrowser.setFocusPolicy(Qt.TabFocus)
		self.FileBrowser.verticalHeader().hide()
		self.FileBrowser.hideColumn(2)
		self.FileBrowser.hideColumn(3)
		self.FileBrowser.setSelectionBehavior(QAbstractItemView.SelectRows)
		self.FileBrowser.setSelectionMode(QAbstractItemView.SingleSelection)
		self.FileBrowser.setSortingEnabled(True)
		self.FileBrowser.sortByColumn(0, Qt.AscendingOrder)
		self.FileBrowser.horizontalHeader().setResizeMode(QHeaderView.Stretch)
		self.FileBrowser.horizontalHeader().setResizeMode(1, QHeaderView.Fixed)
		self.FileBrowser.horizontalHeader().setHighlightSections(False)
		RootIndex = self.FileSystemModel.index(self.rootPath)
		self.FileBrowser.setRootIndex(RootIndex)
		self.FileBrowser.setEditTriggers(QAbstractItemView.NoEditTriggers)
		self.FileBrowser.setTabKeyNavigation(False)

		
#Playlist Lable:
		self.PlaylistLabel = QLabel()
		self.PlaylistLabel.setText("Playlist")
		self.PlaylistLabel.setObjectName("PlaylistLabel")

#PlayListModel:
		self.PlaylistModel = QStandardItemModel()
		playlistHeaderLabels = QStringList()
		playlistHeaderLabels.append("Song")
		#~ playlistHeaderLabels.append("Time")
		self.PlaylistModel.setHorizontalHeaderLabels(playlistHeaderLabels)
		
		
		

#PlayList:
		self.Playlist = PlayList()
		self.Playlist.setMinimumSize(QSize(330, 300))
		self.Playlist.setObjectName("Playlist")
		self.Playlist.setModel(self.PlaylistModel)
		#~ self.Playlist.setFocusPolicy(Qt.TabFocus)
		self.Playlist.setSelectionBehavior(QAbstractItemView.SelectRows)
		self.Playlist.setSelectionMode(QAbstractItemView.SingleSelection)
		self.Playlist.horizontalHeader().setResizeMode(QHeaderView.Stretch)
		self.Playlist.horizontalHeader().setHighlightSections(False)
		self.Playlist.verticalHeader().setHighlightSections(True)
		#~ self.Playlist.horizontalHeader().setResizeMode(1, QHeaderView.Fixed)
		self.Playlist.setEditTriggers(QAbstractItemView.NoEditTriggers)
		self.Playlist.setTabKeyNavigation(False)
		
		
#Volume Label:
		self.VolumeLabel = QLabel()
		self.VolumeLabel.setText("Volume:")
		self.VolumeLabel.setObjectName("VolumeLabel")
		
#Volume Slider:
		self.VolumeSlider = QSlider()
		self.VolumeSlider.setOrientation(Qt.Horizontal)
		self.VolumeSlider.setObjectName("VolumeSlider")
		self.VolumeSlider.setFocusPolicy(Qt.NoFocus)
		self.VolumeSlider.setMinimum(0)
		self.VolumeSlider.setTickInterval(1)
		self.VolumeSlider.setSingleStep(1)
		self.VolumeSlider.setMaximum(100)
		value = self.playCore.getVolume()
		self.VolumeSlider.setValue(value)
		self.VolumeSlider.setMaximumWidth(300)
		self.VolumeSlider.setMinimumWidth(250)
		
#Stream Buffer Label:
		self.StreamBufferLabel = QLabel()
		self.StreamBufferLabel.setText("Stream Buffer:")
		self.StreamBufferLabel.setObjectName("StreamBufferLabel")
		
#Stream Buffer Progress Bar:
		self.StreamBufferProgressBar = QProgressBar()
		#~ self.setProperty("value", 0)
		self.StreamBufferProgressBar.setMinimum(0)
		self.StreamBufferProgressBar.setMaximum(100)
		self.StreamBufferProgressBar.setValue(0)
		self.setObjectName("StreamBufferProgressBar")
		self.StreamBufferProgressBar.setMaximumWidth(300)
		self.StreamBufferProgressBar.setMinimumWidth(225)
		
#Setup Layout:
		self.HorizontalLayout1 = QHBoxLayout()
		self.HorizontalLayout1.addWidget(self.VolumeLabel)
		self.HorizontalLayout1.addWidget(self.VolumeSlider)
		self.HorizontalLayout1.addStretch()
		
		self.HorizontalLayout2 = QHBoxLayout()
		self.HorizontalLayout2.addWidget(self.StreamBufferLabel)
		self.HorizontalLayout2.addWidget(self.StreamBufferProgressBar)
		self.HorizontalLayout2.addStretch()
		
		self.VerticalLayout1 = QVBoxLayout()
		self.VerticalLayout1.addWidget(self.FilesLabel)
		self.VerticalLayout1.addWidget(self.FileBrowser)
		self.VerticalLayout1.addLayout(self.HorizontalLayout1)
		
		self.VerticalLayout2 = QVBoxLayout()
		self.VerticalLayout2.addWidget(self.PlaylistLabel)
		self.VerticalLayout2.addWidget(self.Playlist)
		self.VerticalLayout2.addLayout(self.HorizontalLayout2)
		
		self.HorizontalLayout3 = QHBoxLayout()
		self.HorizontalLayout3.addLayout(self.VerticalLayout1)
		self.HorizontalLayout3.addLayout(self.VerticalLayout2)
		
		self.HorizontalLayout4 = QHBoxLayout()
		self.HorizontalLayout4.addWidget(self.SongLabel)
		self.HorizontalLayout4.addWidget(self.TimeLabel)
		
		self.VerticalLayout3 = QVBoxLayout()
		self.VerticalLayout3.addLayout(self.HorizontalLayout4)
		self.VerticalLayout3.addWidget(self.TrackSlider)
		self.VerticalLayout3.addLayout(self.HorizontalLayout3)
		
		self.FilesLabel.setBuddy(self.FileBrowser)
		self.PlaylistLabel.setBuddy(self.Playlist)
		self.setLayout(self.VerticalLayout3)
		self.setTabOrder(self.FileBrowser, self.Playlist)
		#~ self.setTabOrder(self.Playlist, self.FileBrowser)
		
#Shortcuts:
		self.pauseShortcut = QShortcut(self)
		self.pauseShortcut.setKey('p')
		self.stopShortcut = QShortcut(self)
		self.stopShortcut.setKey('s')
		self.nextShortcut = QShortcut(self)
		self.nextShortcut.setKey('n')
		self.prevShortcut = QShortcut(self)
		self.prevShortcut.setKey('r')
		self.clearShortcut = QShortcut(self)
		self.clearShortcut.setKey('c')
		self.delShortcut = QShortcut(self)
		self.delShortcut.setKey('d')
		
		self.tagReader = TagReader()
		self.mutex = threading.Lock()
		self.connect(self.FileBrowser, SIGNAL("addFile(QString, QString)"), self.addItem)
		self.connect(self.FileBrowser, SIGNAL("addFolder(QString)"), self.addFolder)
		self.connect(self.Playlist, SIGNAL("playSong(QString, QString)"), self.playSong)
		self.connect(self.playCore, SIGNAL("newTags(QString)"), self.changeTags)
		self.connect(self.playCore, SIGNAL("newTimeTag(QString)"), self.changeTime)
		self.connect(self.playCore, SIGNAL("newDuration(int)"), self.newDuration)
		self.connect(self.playCore, SIGNAL("newTimePosition(int)"), self.newTimePosition)
		self.connect(self.TrackSlider, SIGNAL("sliderPressed()"), lambda: self.playCore.changeSeaking(False))
		self.connect(self.TrackSlider, SIGNAL("sliderReleased()"), self.newTrackPosition)
		self.connect(self.TrackSlider, SIGNAL("valueChanged(int)"), self.changeTrackPosition)
		self.connect(self.VolumeSlider, SIGNAL("valueChanged(int)"), self.playCore.setVolume)
		self.connect(self.playCore, SIGNAL("eos()"), self.Playlist.nextSong)
		self.connect(self, SIGNAL("pause()"), self.playCore.pause)
		self.connect(self, SIGNAL("stop()"), self.stop)
		self.connect(self.pauseShortcut, SIGNAL("activated()"), self.playCore.pause)
		self.connect(self.stopShortcut, SIGNAL("activated()"), self.stop)
		self.connect(self.FileBrowser, SIGNAL("addM3U(QString)"), self.addM3U)
		self.connect(self.nextShortcut, SIGNAL("activated()"), self.Playlist.nextSong)
		self.connect(self.prevShortcut, SIGNAL("activated()"), self.Playlist.prevSong)
		self.connect(self.playCore, SIGNAL("buffer(int)"), self.newBuffer)
		self.connect(self.clearShortcut, SIGNAL("activated()"), self.Playlist.removeAll)
		self.connect(self.delShortcut, SIGNAL("activated()"), self.Playlist.delItem)

	def newBuffer(self, buf):
		self.StreamBufferProgressBar.setValue(buf)

	def stop(self):
		self.StreamBufferProgressBar.setValue(0)
		self.playCore.stop()
			
	def addItem2Playlist(self, path, name):
		self.mutex.acquire()
		if path.startsWith("file://"):
			ItemName = QStandardItem(path)
			canonicPath = path.section("file://", 1)
			artistTitle = self.tagReader.getTag(canonicPath)
			if artistTitle == None:
				artistTitle = name
			PlaylistItem = QStandardItem(QString(artistTitle))
			PlaylistItem.insertColumn(0, [ItemName])
			self.PlaylistModel.appendRow(PlaylistItem)
		elif path.startsWith("http://"):
			ItemName = QStandardItem(path)
			artistTitle = name
			PlaylistItem = QStandardItem(QString(artistTitle))
			PlaylistItem.insertColumn(0, [ItemName])
			self.PlaylistModel.appendRow(PlaylistItem)
		self.mutex.release()

	def parseM3U(self, filePath):
		self.mutex.acquire()
		streamExp = QRegExp("^[a-z]{3,5}(:{1}(?!:))(/{2}(?!/))")
		winAbsExp = QRegExp("^[A-Z]{1}(:{1}(?!:))(\\\\{1}(?!\\\\|:|/))")
		nixAbsExp = QRegExp("^/{1}(?!/|:|\\\\)")
		relPathExp = QRegExp("^(\c+|\d+)")
		commentExp = QRegExp("^#")
		File = QFile(filePath)
		if File.open(QFile.ReadOnly | QFile.Text):
			stream = QTextStream(File)
			while True:
				line = stream.readLine()
				if line.isNull(): break
				elif line.contains(commentExp):
					pass
				elif line.contains(streamExp):
					path = line
					name = line.section("/", -1)
					self.addItem(path, name)
				elif line.contains(winAbsExp):
					if QFile(line).exists():
						path = line
						name = line.section("\\", -1)
						self.addItem("file://"+path, name)
				elif line.contains(nixAbsExp):
					if QFile(line).exists():
						path = line
						name = line.section("/", -1)
						self.addItem("file://"+path, name)
				elif line.contains(relPathExp):
					if line.contains("\\") and not line.contains("/"):
						path = filePath.section('\\',0,-2) + "\\" + line
						if QFile(path).exists():
							name = path.section("\\", -1)
							self.addItem("file://"+path, name)
					elif line.contains("/") and not line.contains("\\"):
						path = filePath.section('/',0,-2) + "/" + line
						if QFile(path).exists():
							name = path.section("/", -1)
							self.addItem("file://"+path, name)
					else:
						path = filePath.section('/',0,-2) + "/" + line
						if QFile(path).exists():
							name = path.section("/", -1)
							self.addItem("file://"+path, name)
		File.close()
		self.mutex.release()
		
	def addItem(self, _path, _name):
		path = QString(_path)
		name = QString(_name)
		fileThread = threading.Thread(target = self.addItem2Playlist, args=[path, name])
		fileThread.start()
	
	def addM3U(self, filePath):
		fileThread = threading.Thread(target = self.parseM3U, args=[filePath])
		fileThread.start()
		
	def addFolder(self, folderPath):
		for fileName in QDir(folderPath).entryList(self.FileFilter_2, filters = QDir.Files):
			filePath = "file://" + folderPath + "/" + fileName
			self.addItem(filePath, fileName)
	
	def restorePlaylist(self, Items):
		for path in Items:
			if path.startsWith("file://"):
				name = path.split("/")
				fileName = name.takeLast()
				self.addItem(path, fileName)
			elif path.startsWith("http://"):
				name = path.split("/")
				streamName = name.takeLast()
				self.addItem(path, streamName)
			
	def getPlaylist(self):
		files = QStringList()
		for row in range(self.PlaylistModel.rowCount()):
			index = self.PlaylistModel.index(row, 0)
			item = self.PlaylistModel.itemFromIndex(index)
			files.append(item.child(0,0).text())
		return files
			
	def changeTags(self, tags):
		self.SongLabel.setText("<font size=4><b>" + tags + "</b></font>")
		
	def changeTime(self, time):
		self.TimeLabel.setText("<font size=3><b>" + time + "</b></font>")
		
	def newDuration(self, dur):
		self.TrackSlider.setMaximum(dur)
		
	def newTimePosition(self, pos):
		self.TrackSlider.setValue(pos)
		
	def newTrackPosition(self):
		pos = self.TrackSlider.sliderPosition()
		self.playCore.changeTrackPosition(pos)
		self.playCore.changeSeaking(True)
	
	def changeTrackPosition(self, pos):
		if self.playCore.seaking == False:
			self.playCore.changeTrackPosition(pos)
		else: pass
		
	def nextSong(self):
		nextFile = self.Playlist.nextSong()
		if nextFile == False:
			pass
		self.playCore.start_stop(nextFile)
	
	def playSong(self, fileName, tags):
		self.changeTags(tags)
		self.playCore.play(fileName)
		
	def play(self):
		self.Playlist.play()
	
class MainWindow(QMainWindow):
	def __init__(self, parent = None):
		super(MainWindow, self).__init__(parent)
		#~ self.setFocus(Qt.MenuBarFocusReason)
		settings = QSettings()
		rootPath = settings.value("RootPath").toString()
		if rootPath == None: rootPath = QDir.rootPath()
		pls = settings.value("Playlist")
		if not pls.isValid():
			playlist = None
		else:
			playlist = pls
		self.playlist = pls.toStringList()
		self.restoreGeometry(settings.value("Geometry").toByteArray())
# MainWidget:
		self.mainWidget = MainWidget(rootPath)
		self.setCentralWidget(self.mainWidget)
# File Menu:
		self.fileMenu = self.menuBar().addMenu("&File")
		self.fileMenu.setObjectName("FileMenu")
# Navigation Menu:
		self.navigationMenu = self.menuBar().addMenu("&Navigation")
		self.navigationMenu.setObjectName("NavigationMenu")
# Playlist Menu:
		self.playlistMenu = self.menuBar().addMenu("&Playlist")
		self.playlistMenu.setObjectName("PlaylistMenu")
# Actions:
		fileMenu_QuitAction = QAction("Quit", self)
		fileMenu_QuitAction.setToolTip("Exit")
		fileMenu_QuitAction.setStatusTip("Exit")
		self.connect(fileMenu_QuitAction, SIGNAL("triggered()"), self.close)
		
		navigationMenu_PlayAction = QAction("Play	p", self)
		navigationMenu_PlayAction.setToolTip("Play")
		navigationMenu_PlayAction.setStatusTip("Play")
		self.connect(navigationMenu_PlayAction, SIGNAL("triggered()"), self.mainWidget.play)
		
		navigationMenu_StopAction = QAction("Stop	s", self)
		navigationMenu_StopAction.setToolTip("Stop")
		navigationMenu_StopAction.setStatusTip("Stop")
		self.connect(navigationMenu_StopAction, SIGNAL("triggered()"), self.mainWidget.playCore.stop)
		
		navigationMenu_PauseAction = QAction("Pause	p", self)
		navigationMenu_PauseAction.setToolTip("Pause")
		navigationMenu_PauseAction.setStatusTip("Pause")
		self.connect(navigationMenu_PauseAction, SIGNAL("triggered()"), self.mainWidget.playCore.pause)

		navigationMenu_NextAction = QAction("Next	n", self)
		navigationMenu_NextAction.setToolTip("Next")
		navigationMenu_NextAction.setStatusTip("Next")
		self.connect(navigationMenu_NextAction, SIGNAL("triggered()"), self.mainWidget.Playlist.nextSong)
				
		navigationMenu_PrevAction = QAction("Prev	r", self)
		navigationMenu_PrevAction.setToolTip("Previous")
		navigationMenu_PrevAction.setStatusTip("Previous")
		self.connect(navigationMenu_PrevAction, SIGNAL("triggered()"), self.mainWidget.Playlist.prevSong)

		playlistMenu_DelAction = QAction("Del entry	d", self)
		playlistMenu_DelAction.setToolTip("Delete entry")
		playlistMenu_DelAction.setStatusTip("Delete entry")
		self.connect(playlistMenu_DelAction, SIGNAL("triggered()"), self.mainWidget.Playlist.delItem)
		
		playlistMenu_ClearAction = QAction("Clear		c", self)
		playlistMenu_ClearAction.setToolTip("Clear playlist")
		playlistMenu_ClearAction.setStatusTip("Clear playlist")
		self.connect(playlistMenu_ClearAction, SIGNAL("triggered()"), self.mainWidget.Playlist.removeAll)
# Add actions in menu:
		self.fileMenu.addAction(fileMenu_QuitAction)
		self.navigationMenu.addAction(navigationMenu_PlayAction)
		self.navigationMenu.addAction(navigationMenu_StopAction)
		self.navigationMenu.addAction(navigationMenu_PauseAction)
		self.navigationMenu.addAction(navigationMenu_NextAction)
		self.navigationMenu.addAction(navigationMenu_PrevAction)
		self.playlistMenu.addAction(playlistMenu_DelAction)
		self.playlistMenu.addAction(playlistMenu_ClearAction)
		
		
		QTimer.singleShot(0, lambda: self.mainWidget.restorePlaylist(self.playlist))
		
	def closeEvent(self, event):
		settings = QSettings()
		path = self.mainWidget.FileSystemModel.filePath(self.mainWidget.FileBrowser.rootIndex())
		if path == None: path = QDir.rootPath()
		pls = self.mainWidget.getPlaylist()
		playlist = QVariant(pls)
		rootPath = QVariant(path)
		settings.setValue("RootPath", rootPath)
		settings.setValue("Playlist", playlist)
		settings.setValue("Geometry", QVariant(self.saveGeometry()))
		
		
def main():
	gobject.threads_init()
	app = QApplication(sys.argv)
	app.setOrganizationName("konjoot corp.")
	app.setOrganizationDomain("konjoot.org")
	app.setApplicationName("EasyPlay")
	#~ app.setWindowIcon(QIcon(":/icon.png"))
	form = MainWindow()
	form.show()
	app.exec_()
	

if __name__ == '__main__':
	main()
	
